#include "aig.h"
#include "cktname.h"

#include <iostream>
#include <fstream>
#include <cstring>
using std::cout;
using std::endl;
using std::ofstream;

/******************************************************************************
 *    AIG format utilization parsing function
*******************************************************************************/
static unsigned char
getnoneofch (FILE * file)
{
  int ch = getc (file);
  if (ch != EOF)
    return ch;

  fprintf (stderr, "*** decode: unexpected EOF\n");
  exit (1);
}
static unsigned
decode (FILE * file)
{
  unsigned x = 0, i = 0;
  unsigned char ch;

  while ((ch = getnoneofch (file)) & 0x80)
    x |= (ch & 0x7f) << (7 * i++);

  return x | (ch << (7 * i));
}
static void
encode (FILE * file, unsigned x)
{
  unsigned char ch;

  while (x & ~0x7f)
    {
      ch = (x & 0x7f) | 0x80;
      putc (ch, file);
      x >>= 7;
    }

  ch = x;
  putc (ch, file);
}
//inline AigLit   aigdecode(unsigned i ){ return toAigLit( i>>1 , i&1 ); }
//inline unsigned aigencode(AigLit   p ){ unsigned i = p.idx; return (i<<1)|p.sign ;}
inline AigLit   aigdecode(unsigned i ){ return i; }
inline unsigned aigencode(AigLit   p ){ return p;}

//=============================================================================
//[Synopsis]    read initialization 
//=============================================================================
void StrashAIG::read_initialization( unsigned I , unsigned L , unsigned O , unsigned M )
{
   _ppiFlag = 1+I ;
   _andFlag = 1+I+L;

   _po .growTo( O + L );

   capacity( M+1 );
   for( unsigned i = 1 ; i < _andFlag ; ++i)createBase();
}
bool StrashAIG::read_aig( const char * str , CktName * names)
{
   FILE * f = fopen( str , "rb" );
   if( f ==NULL ) {printf("wrong open %s \n", str); return false;}

   char c_tmp[10]; 
   unsigned M , I , L , O , A , id , lhs , rhs0 , rhs1 ;
   fscanf (f, "%s%d%d%d%d%d", c_tmp, &M, &I, &L, &O, &A);
   assert (strcmp (c_tmp, "aig") == 0 && M == I + L + A);

   read_initialization( I , L , O , M );
   if( names ) names->initialize( I , L , O );

   for( unsigned i = 0 ; i < L+O ; ++i )
   {
      fscanf( f , "%d" , &id );
      _po[i] = aigdecode( id ) ; 
   }

   decode( f );
   AigLit * lut = new AigLit[(M+1)<<1];
   for( unsigned i = 0 , j =0 ; i < _andFlag ; ++ i , j+=2) lut[j]=j,lut[j+1]=j+1;
   for (unsigned int i = 0, j = I + L + 1; i < A; ++i, ++j )
   {
      lhs = j << 1;
      rhs0 = lhs - decode (f);
      rhs1 = rhs0 - decode (f);
      AigLit p = createAND( lut[aigdecode(rhs1)], lut[aigdecode(rhs0)] );
      lut[ lhs ] = p , lut[ lhs +1 ] = inv(p);
   }
   if( (unsigned)sz != M+1 )
   { 
      cout << "Error > Wrong aig format" << endl;
      for( unsigned i = 0 ; i < _po.size() ; ++ i ) _po[i] = lut[ _po[i]];
   }
   delete [] lut;
   if( names )names->read_aig( f );
   fclose( f );

   return true;
}

static unsigned index( unsigned var , unsigned sign){ return (var+var)+sign;}
inline unsigned index( AigLit p ){return p;}

static void writeAnd( FILE * f , unsigned i , unsigned a , unsigned b )
{
   if( a < b ) std::swap( a , b) ;
   encode( f , i -  a);
   encode( f , a-b);
}
bool StrashAIG::write_aig( const char * str , CktName * names)const
{
   FILE * f =  fopen( str , "wb");
   if( f ==NULL ) {printf("wrong open %s \n", str); return false;}

   unsigned M = size()-1;
   unsigned I = _ppiFlag -1;
   unsigned L = _andFlag - _ppiFlag;
   unsigned O = _po.size()-L;
   unsigned A = M-I-L;

   fprintf( f , "aig %d %d %d %d %d\n", M, I, L, O , A );
     
   for( unsigned i = 0 ; i < _po.size(); ++i)
      fprintf( f, "%d\n" , index( _po[i]));

   for( unsigned i = _andFlag ; i < size() ; ++i )
      writeAnd( f, index( i , 0  ) , 
                   index( (*this)[i].fanin[0] ) , 
                   index( (*this)[i].fanin[1]  ) );

   if( names ) names->write_aig ( f );

   fclose( f);
   return true;
}
void StrashAIG::report()const
{
   cout<< "M I L O A " << 
         size()-1            <<"\t"<< 
         _ppiFlag-1          <<"\t"<< 
         _andFlag-_ppiFlag   <<"\t"<< 
         _po.size()          <<"\t"<< 
         size() - _andFlag 
      <<endl;
}
static const char * _color[] = {"white","red","blue"};
static const char * Color( unsigned char i ){return _color[i];}
void StrashAIG::write_dot( const char * file , unsigned char * color )const
{
   ofstream out ( file );

   out<< "digraph network { " << endl;
   out<< "center = true ;"<<endl;
   out<< "rotate = 180;" <<endl;
   out<< "node[style=filled];"<<endl;
   out<< "size=\"20,20\";"<<endl;

   for( unsigned i = _andFlag ; i < size() ; ++ i)
   {
      AigNode n = (*this)[i];
      out << var(n.fanin[0]) << " -> " << i << "[style = " << (sign(n.fanin[0]) ? "dotted" : "bold") << " ] ;" <<endl;
      out << var(n.fanin[1]) << " -> " << i << "[style = " << (sign(n.fanin[1]) ? "dotted" : "bold") << " ] ;" <<endl;

      if( color ) out << i << " [ fillcolor = " << Color( color[i] ) << " ]; " ;
   }
   for( unsigned i = 0 ; i < _andFlag ; ++ i ) 
   {
      out << i << "[ shape = invtriangle ]; " << endl;
      if( color ) out << i << " [ fillcolor = " << Color( color[i] ) << " ]; " ;
   }
   for( unsigned i = 0 ; i < _po.size() ; ++i )
   {
      out << var( _po[i] ) << "[ shape = triangle ]; " << endl;
   }
   out<< "}" <<endl;
}
